<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  version="2.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2"
	xmlns:ebforms="http://code.google.com/p/eb-forms"
	xmlns:ebfuncs="http://code.google.com/p/eb-forms/functions">
	
	<xsl:import href="GlobalVars.xsl"/>
	<xsl:import href="GlobalFunctions.xsl"/>
	
	<!-- 
		Returns all child element for parent and there position if it is defined in the annotations file.
		Otherwise the position will be 99999 so that they wil come after the the elements that have
		an position defined in the annotations file.
		@parent 			- 	The parent element from which to get the children.
		@parent.schema 	- 	The schema in which the element is declared. This can be ommitted when
		the element is in the rootschema.
	-->
	<xsl:template name="GetChildElements">
		<xsl:param name="parent" as="xsd:string" required="yes"/>
		<xsl:param name="parent.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="complexType" 
			select="document( $parent.schema )//xsd:complexType[@name = $parent ]" />
		
		<xsl:for-each select="$complexType/xsd:sequence/xsd:element">
			<xsl:variable name="den" select="ebfuncs:getDen( $complexType )" />
			<xsl:copy>
				<xsl:copy-of select="@*" />
				<xsl:copy-of select="*" />
				<xsl:choose>
					<xsl:when test="$global.doc.annotations/annotations
						/core-component[@den = $den]/position">
						<xsl:copy-of
							select="$global.doc.annotations/annotations
								/core-component[@den = $den]/position" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:element name="position">99999</xsl:element>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:copy>
		</xsl:for-each>
	</xsl:template>
	
	<!--
		Returns the document in which the datatype is defined.
		@element.type - The element type for which the schema is looked up.
		@element.schema- The document in which the datatype is used (not defined).
		
		Note I: This template isn't very advanced at the moment. It asumes that the document in which
		the dataType is used also imports the document where the datatype is declared.
		
		Note II: The dataType variable must contain the namespace prefix of the namespace in 
		which the datatype is declared.
	-->
	<xsl:template name="GetDataTypeDocument" >
		<xsl:param name="element.type" as="xsd:string" required="yes"/>
		<xsl:param name="element.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="element.type.prefix" select="substring-before( $element.type, ':' )" />
		
		<xsl:variable name="element.type.ns" 
			select="if( $element.schema = '' ) 
			then $global.doc.schema.root/xsd:schema/namespace::*[name() = $element.type.prefix ]
			else document( $element.schema )/xsd:schema/namespace::*[name() = $element.type.prefix ]" />
		
		<xsl:variable name="element.schema.ns" select="if( $element.schema = '' ) 
			then $global.doc.schema.root/xsd:schema/@targetNamespace
			else document( $element.schema )/xsd:schema/@targetNamespace" />
		
		<xsl:choose>
			<xsl:when test="$element.schema.ns != $element.type.ns">
				<xsl:variable name="element.type.schema" select="if( $element.schema = '' )
					then $global.doc.schema.root/xsd:schema/xsd:import[
						@namespace = $element.type.ns]/@schemaLocation
					else document( $element.schema )/xsd:schema/xsd:import[
						@namespace = $element.type.ns]/@schemaLocation"/>
				<xsl:value-of select="document-uri( document( $element.type.schema ) )" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:sequence select="$element.schema" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<!-- 
		This template looks up the dictionairy entry name for the parent of the element
		with given den.
		
		@param den - the dictionairy entry name of the element for which to look up the parent
		@param element.type - should always be the type of the root element of the current 
		document.
		@param element.schema - the schema where element.type is declared.
	-->
	<xsl:template name="GetParentDen" >
		<xsl:param name="den.search" required="yes" />
		<xsl:param name="element.den" required="yes" />
		<xsl:param name="element.type" as="xsd:string" required="yes" />
		<xsl:param name="element.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="element.children">
			<xsl:call-template name="GetChildElements">
				<xsl:with-param name="parent" select="substring-after( $element.type, ':' )" />
				<xsl:with-param name="parent.schema" select="$element.schema" />
			</xsl:call-template>			
		</xsl:variable>
		
		<xsl:for-each select="$element.children/xsd:element">
			<xsl:variable name="den.current" as="xsd:string" select="ebfuncs:getDen( . )"/>
			
			<xsl:choose>
				<xsl:when test="$den.current = $den.search">
					<xsl:value-of select="$element.den" />					
				</xsl:when>
				<xsl:when test="not( xsd:annotation/xsd:documentation/ccts:Acronym = 'BBIE' )">
					<xsl:variable name="element.child.type.document">
						<xsl:call-template name="GetDataTypeDocument">
							<xsl:with-param name="element.type" select="@type" />
							<xsl:with-param name="element.schema" select="$element.schema"/>
						</xsl:call-template>
					</xsl:variable>
					
					<xsl:call-template name="GetParentDen">
						<xsl:with-param name="den.search" select="$den.search"/>
						<xsl:with-param name="element.den" select="ebfuncs:getDen( . )" />
						<xsl:with-param name="element.type" select="@type" />
						<xsl:with-param name="element.schema" select="$element.child.type.document" />
					</xsl:call-template>
				</xsl:when>
			</xsl:choose>
		</xsl:for-each>
	</xsl:template>
	
	<!-- 
		This template returns the default value for a CoreComponent with given dictionary entry name.
	-->
	<xsl:template name="GetDefaultValue">
		<xsl:param name="element.den" as="xsd:string" required="yes"/>
		
		<xsl:value-of select="$global.doc.annotations/annotations/core-component[
			@den = $element.den]/default-value" />
	</xsl:template>
	
	<!-- 
		Returns the name of the type on which element.type is based.
	-->
	<xsl:template name="GetBaseType" as="xsd:string">
		<xsl:param name="element.type" as="xsd:string" required="yes" />
		<xsl:param name="element.type.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="type" select="substring-after( $element.type, ':' )" />
		
		<xsl:variable name="element.type.def" 
			select="if( exists( document( $element.type.schema )/xsd:schema/xsd:complexType[@name = $type] ) )
				then document( $element.type.schema )/xsd:schema/xsd:complexType[@name = $type]
				else document( $element.type.schema )/xsd:schema/xsd:simpleType[@name = $type]" />
		
		<xsl:value-of select="if( exists( $element.type.def/xsd:restriction/@base ) )
			then $element.type.def/xsd:restriction/@base
			else $element.type.def/xsd:simpleContent/xsd:restriction/@base" />
	</xsl:template>
	
	<!-- 
		Looks for the unqualfied datatype on which this qualified datatype is based.
		
		@element.type - The type for which to look up on which Unqualified Data Type it's based.
		@element.type.schema - The document in which the element.type is defined
	-->
	<xsl:template name="GetUnqualifiedDataType" as="xsd:string">
		<xsl:param name="element.type" as="xsd:string" required="yes" />
		<xsl:param name="element.type.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="element.type.base" >
			<xsl:call-template name="GetBaseType">
				<xsl:with-param name="element.type" select="$element.type" />
				<xsl:with-param name="element.type.schema" select="$element.type.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<xsl:choose>
			<!--
				According to the spec each unqualified datatype should be in a namespace 
				with prefix udt. See section 7.6.3 of the XML NDS.
				
				First case:  element.type is itself an unqualified data type.
			-->
			<xsl:when test="substring-before( $element.type, ':' ) = 'udt' ">
				<xsl:value-of select="$element.type" />
			</xsl:when>
			<!-- 
				Second case: element.type is a qualified datatype. This can either be:
				- based on another qualified datatype
				- based on an unqualified datatype
				- or it's an simpletype
			-->
			<xsl:when test="substring-before( $element.type, ':' ) = 'qdt' ">
				<xsl:choose>
					<xsl:when test="substring-before( $element.type.base, ':' ) = 'qdt'">
						<xsl:variable name="element.basetype.schema">
							<xsl:call-template name="GetDataTypeDocument">
								<xsl:with-param name="element.type" select="$element.type.base" />
								<xsl:with-param name="element.schema" select="$element.type.schema" />						
							</xsl:call-template>
						</xsl:variable>
						<xsl:call-template name="GetUnqualifiedDataType">
							<xsl:with-param name="element.type" select="$element.type.base"/>
							<xsl:with-param name="element.type.schema" select="$element.basetype.schema"/>
						</xsl:call-template>
					</xsl:when>
					<xsl:when test="substring-before( $element.type.base, ':' ) = 'udt'">
						<xsl:value-of select="$element.type.base" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:variable name="element.den" 
							select="document( $element.type.schema )/xsd:schema
							/xsd:simpleType[@name = substring-after( $element.type, ':' )]
							/xsd:annotation/xsd:documentation/ccts:DictionaryEntryName" />
						
						<xsl:choose>
							<xsl:when test="contains( $element.den, 'Code. Type' )">
								<xsl:text>udt:CodeType</xsl:text>
							</xsl:when>
							<xsl:when test="contains( $element.den, 'Identifier. Type' )">
								<xsl:text>udt:IDType</xsl:text>
							</xsl:when>
							<xsl:otherwise>
								<xsl:value-of select="error( 
									QName( 'http://code.google.com/p/eb-forms/functions', 'GetUnqualifiedDataType' )
									, concat( 'GetUnqualifiedDataType: QDT has invalid den, should contain Identifier. Type or Code. Type. element.den: '
									, $element.den )  ) " 
								/>
							</xsl:otherwise>
						</xsl:choose>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="error( 
					QName( 'http://code.google.com/p/eb-forms/functions', 'GetUnqualifiedDataType' )
					, concat( 'GetUnqualifiedDataType: element.type is not an UDT or a QDT '
					, $element.type )  ) " 
				/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template name="BasedOnSimpleType">
		<xsl:param name="element.type" as="xsd:string" required="yes" />
		<xsl:param name="element.type.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="element.type.base" >
			<xsl:call-template name="GetBaseType">
				<xsl:with-param name="element.type" select="$element.type" />
				<xsl:with-param name="element.type.schema" select="$element.type.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<xsl:choose>
			<!--	First case:  element.type is itself an unqualified data type. -->
			<xsl:when test="substring-before( $element.type, ':' ) = 'udt'">
				<xsl:value-of select="false()" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:choose>
					<xsl:when test="substring-before( $element.type.base, ':' ) = 'qdt'">
						<xsl:variable name="element.basetype.schema">
							<xsl:call-template name="GetDataTypeDocument">
								<xsl:with-param name="element.type" select="$element.type.base" />
								<xsl:with-param name="element.schema" select="$element.type.schema" />						
							</xsl:call-template>
						</xsl:variable>
						<xsl:call-template name="BasedOnSimpleType">
							<xsl:with-param name="element.type" select="$element.type.base"/>
							<xsl:with-param name="element.type.schema" select="$element.basetype.schema"/>
						</xsl:call-template>
					</xsl:when>
					<xsl:when test="substring-before( $element.type.base, ':' ) = 'udt'">
						<xsl:value-of select="false()" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="true()" />
					</xsl:otherwise>
				</xsl:choose>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template name="GetAttributes" as="item()*">
		<xsl:param name="type" as="xsd:string" required="yes" />
		<xsl:param name="type.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="type.base.unqualified">
			<xsl:call-template name="GetUnqualifiedDataType">
				<xsl:with-param name="element.type" select="$type" />
				<xsl:with-param name="element.type.schema" select="$type.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<xsl:variable name="type.base.schema">
			<xsl:call-template name="GetDataTypeDocument">
				<xsl:with-param name="element.type" select="$type.base.unqualified" />
				<xsl:with-param name="element.schema" select="$type.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<xsl:for-each select="document( $type.base.schema )
			/xsd:schema/xsd:complexType[@name = substring-after( $type.base.unqualified, ':' )]
				/xsd:simpleContent/xsd:extension/xsd:attribute">
			<xsl:element name="attribute">
				<xsl:attribute name="name" select="@name" />
				<xsl:attribute name="type" select="@type" />
			</xsl:element>
		</xsl:for-each>
	</xsl:template>
	
	<xsl:template name="GetUnusedAttributes" as="item()*" >
		<xsl:param name="element.den" as="xsd:string" required="yes" />
		
		<xsl:sequence select="$global.doc.annotations/annotations/core-component
			[@den = $element.den]/unused-attributes/attribute" />
	</xsl:template>
	
	<xsl:template name="GetUsedAttributes" as="item()*">
		<xsl:param name="element.den" as="xsd:string" required="yes" />
		<xsl:param name="element.type" as="xsd:string" required="yes" />
		<xsl:param name="element.type.schema" as="xsd:string" required="yes" />
		
		<xsl:variable name="element.type.isRestrictedSimpleType">
			<xsl:call-template name="BasedOnSimpleType">
				<xsl:with-param name="element.type" select="$element.type" />
				<xsl:with-param name="element.type.schema" select="$element.type.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<!-- 
			If element.type.isRestrictedSimpleType is true then whe have a qdt that is a restricted
			xsl:simpleType. This means that it for sure has no attributes. Otherwhise whe have to
			look up the attributes.
		-->
		<xsl:if test="$element.type.isRestrictedSimpleType = false()">
			<xsl:variable name="element.type.attributes">
				<xsl:call-template name="GetAttributes" >
					<xsl:with-param name="type" select="$element.type" />
					<xsl:with-param name="type.schema" select="$element.type.schema" />
				</xsl:call-template>
			</xsl:variable>
			
			<xsl:variable name="element.type.attributes.unused">
				<xsl:call-template name="GetUnusedAttributes" >
					<xsl:with-param name="element.den" select="xsd:annotation/xsd:documentation/ccts:DictionaryEntryName" />
				</xsl:call-template>
			</xsl:variable>
			
			<xsl:for-each select="$element.type.attributes/attribute">
				<xsl:variable name="name" select="@name" />
				<xsl:variable name="type" select="@type" />
				<xsl:if test="count( $element.type.attributes.unused/attribute[@name = $name] ) = 0">
					<xsl:element name="attribute">
						<xsl:attribute name="name" select="$name" />
						<xsl:attribute name="type" select="$type" />
					</xsl:element>
				</xsl:if>
			</xsl:for-each>
		</xsl:if>
	</xsl:template>
	
	<xsl:template name="GetAttributeInfo">
		<xsl:param name="type" as="xsd:string" required="yes" />
		<xsl:param name="type.schema" as="xsd:string" required="yes" />
		<xsl:param name="type.attribute" as="xsd:string" required="yes" />
		
		<xsl:variable name="attribute.type" 
			select="document( $type.schema )/xsd:schema/xsd:complexType
			[@name = substring-after( $type, ':' )]/xsd:simpleContent/xsd:extension/xsd:attribute
			[@name = $type.attribute]/@type" />
		
		<xsl:choose>
			<!-- 
				If the attribute type is empty and whe have an unqualified datatype then return
				nothing
			-->
			<xsl:when test="not( $attribute.type ) and substring-before( $type, ':' ) = 'udt' " >
				<xsl:value-of select="error( QName( 'E', 'E' ), concat( 'GlobalTemplates.xsl : GetAttributeInfo : attribute ', $type.attribute, ' does not excist for ', $type ) )" />
			</xsl:when>
			
			<!-- 
				If the attribute type is empty and whe have an qualified datatype then we have
				to look up the basetype of this datatype and check if the type of the attribute is
				declared there.
			-->
			<xsl:when test="not( $attribute.type ) and not( substring-before( $type, ':' ) = 'udt' )">
				<xsl:variable name="type.base" 
					select="document( $type.schema )/xsd:schema/xsd:complexType
					[@name = substring-after( $type, ':' )]/xsd:simpleContent/xsd:restriction/@base" />
				
				<xsl:variable name="type.base.schema">
					<xsl:call-template name="GetDataTypeDocument">
						<xsl:with-param name="element.type" select="$type.base"/>
						<xsl:with-param name="element.schema" select="$type.schema"/>
					</xsl:call-template>
				</xsl:variable>
				
				<xsl:call-template name="GetAttributeInfo">
					<xsl:with-param name="type" select="$type.base"/>
					<xsl:with-param name="type.schema"  select="$type.base.schema"/>
					<xsl:with-param name="type.attribute" select="$type.attribute" />
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:variable name="attribute.type.schema">
					<xsl:call-template name="GetDataTypeDocument">
						<xsl:with-param name="element.type" select="$attribute.type" />
						<xsl:with-param name="element.schema" select="$type.schema" />
					</xsl:call-template>
				</xsl:variable>
				
				<xsl:element name="attribute">
					<xsl:attribute name="name" select="$type.attribute" />
					<xsl:attribute name="type" select="$attribute.type" />
					<xsl:attribute name="type.schema" select="$attribute.type.schema" />
				</xsl:element>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
</xsl:stylesheet>
